package org.javahispano.javacup.tacticas_aceptadas.kaprichodelsur.jmv;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

import org.javahispano.javacup.modelo.Comando;
import org.javahispano.javacup.modelo.ComandoGolpearBalon;
import org.javahispano.javacup.modelo.ComandoIrA;
import org.javahispano.javacup.modelo.Constantes;
import org.javahispano.javacup.modelo.Posicion;
import org.javahispano.javacup.modelo.SituacionPartido;
import org.javahispano.javacup.modelo.Tactica;
import org.javahispano.javacup.modelo.TacticaDetalle;

public class TacticaJmvCf implements Tactica {

	Posicion alineacion1[]=new Posicion[]{
	        new Posicion(0.2595419847328244,-50.41044776119403),
	        new Posicion(-19.46564885496183,-31.6044776119403),
	        new Posicion(0.0,-31.59502262443439),
	        new Posicion(19.984732824427482,-31.6044776119403),
	        new Posicion(15.454545454545453,-9.502262443438914),
	        new Posicion(-15.692307692307693,-11.165158371040723),
	        new Posicion(-20.923076923076923,16.628959276018097),
	        new Posicion(24.48951048951049,16.153846153846153),
	        new Posicion(-2.6153846153846154,34.920814479638004),
	        new Posicion(-0.4755244755244755,0.0),
	        new Posicion(6.6573426573426575,19.95475113122172)
	    };

	Posicion alineacion2[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-11.16030534351145, -31.082089552238806),
			new Posicion(11.16030534351145, -31.6044776119403),
			new Posicion(27.251908396946565, -27.94776119402985),
			new Posicion(-29.84732824427481, -26.902985074626866),
			new Posicion(8.564885496183205, -7.574626865671642),
			new Posicion(-10.641221374045802, -7.052238805970149),
			new Posicion(27.251908396946565, 4.440298507462686),
			new Posicion(-29.32824427480916, 3.3955223880597014),
			new Posicion(-0.2595419847328244, 19.067164179104477),
			new Posicion(-0.2595419847328244, 35.78358208955224) };

	Posicion alineacion3[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-11.16030534351145, -31.082089552238806),
			new Posicion(11.16030534351145, -31.6044776119403),
			new Posicion(26.732824427480914, -20.111940298507463),
			new Posicion(-29.32824427480916, -21.67910447761194),
			new Posicion(0.2595419847328244, -0.26119402985074625),
			new Posicion(-18.946564885496183, -0.26119402985074625),
			new Posicion(18.946564885496183, -0.26119402985074625),
			new Posicion(-19.46564885496183, 35.78358208955224),
			new Posicion(-0.2595419847328244, 19.067164179104477),
			new Posicion(18.946564885496183, 35.26119402985075) };

	Posicion alineacion4[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-11.16030534351145, -31.082089552238806),
			new Posicion(11.16030534351145, -31.6044776119403),
			new Posicion(28.290076335877863, -28.470149253731343),
			new Posicion(-28.290076335877863, -28.470149253731343),
			new Posicion(11.16030534351145, -1.3059701492537314),
			new Posicion(-10.641221374045802, -0.7835820895522387),
			new Posicion(-27.251908396946565, 31.6044776119403),
			new Posicion(-10.641221374045802, 30.559701492537314),
			new Posicion(9.603053435114505, 28.992537313432837),
			new Posicion(25.69465648854962, 28.992537313432837) };

	Posicion alineacion5[] = new Posicion[] {
			new Posicion(0.2595419847328244, -50.41044776119403),
			new Posicion(-18.307692307692307, -32.782805429864254),
			new Posicion(0.23776223776223776, -33.257918552036195),
			new Posicion(16.167832167832167, -32.782805429864254),
			new Posicion(7.846153846153847, -17.104072398190045),
			new Posicion(-7.132867132867133, -17.34162895927602),
			new Posicion(-18.545454545454543, -7.126696832579185),
			new Posicion(20.685314685314687, -11.402714932126697),
			new Posicion(5.969465648854961, -5.485074626865671),
			new Posicion(0.2595419847328244, -0.26119402985074625),
			new Posicion(11.888111888111888, -2.1380090497737556) };

	Posicion alineacion6[]=new Posicion[]{
	        new Posicion(0.2595419847328244,-50.41044776119403),
	        new Posicion(-11.16030534351145,-35.78358208955224),
	        new Posicion(12.717557251908397,-35.26119402985075),
	        new Posicion(28.290076335877863,-28.470149253731343),
	        new Posicion(0.0,-26.131221719457013),
	        new Posicion(-24.727272727272727,-29.93212669683258),
	        new Posicion(-12.601398601398602,-17.816742081447966),
	        new Posicion(22.349650349650346,-4.038461538461538),
	        new Posicion(7.846153846153847,-7.601809954751132),
	        new Posicion(-0.23776223776223776,-10.214932126696834),
	        new Posicion(-21.874125874125873,-3.088235294117647)
	    };



	TacticaDetalle detalle = new TacticaJmvCfDetalle();

	public TacticaDetalle getDetalle() {
		return detalle;
	}

	public Posicion[] getPosicionSaca(SituacionPartido sp) {
		return alineacion5;
	}

	public Posicion[] getPosicionRecive(SituacionPartido sp) {
		return alineacion6;
	}

	/**
	 * Este m�todo ejecuta las instrucciones que le damos a los jugadores en el
	 * partido.
	 */
	public List<Comando> ejecutar(SituacionPartido sp) {

		LinkedList<Comando> result = new LinkedList<Comando>();

		// vacia la lista de comandos
		result.clear();
		// si voy perdiendo o empatando
		if (sp.golesPropios() <= sp.golesRival()) {
			// cada jugador ubicarse segun alineacion1
			for (int i = 0; i < 11; i++) {
				result.add(new ComandoIrA(i, alineacion1[i]));
			}
		} else {// sino, osea que voy ganando
			// cada jugador ubicarse segun alineacion2
			for (int i = 0; i < 11; i++) {
				result.add(new ComandoIrA(i, alineacion1[i]));
			}
		}

		// Compruebo si tenemos la posicion del bal�n
		int indMasCercano = sp.balon().indiceMasCercano(sp.misJugadores());
		double distanciaMasCercano = sp.balon().distancia(
				sp.misJugadores()[indMasCercano]);
		boolean posesionBalon = false;
		if (distanciaMasCercano <= Constantes.DISTANCIA_CONTROL_BALON) {
			posesionBalon = true;
		}
		boolean esPosiblePosesionBalon = TacticaJmvCfUtils.esPosibleObtenerBalon(sp);

		boolean zonaDefensaActivada = false;
		boolean zonaMedioCampoActivada = false;
		boolean zonaDelanteraActivada = false;
		if (sp.balon().getY() < TacticaJmvCfUtils.ZONA_DEFENSA) {
			zonaDefensaActivada = true;
		} else if (sp.balon().getY() > TacticaJmvCfUtils.ZONA_DELANTERA) {
			zonaDelanteraActivada = true;
		} else {
			// zonaMedioCampo = (<= zonaDelantera y >= zonaDefensa)
			zonaMedioCampoActivada = true;
		}

		// El jugador mas cercano al balon va detras de �l.
		// Si se desea hacer otra cosa se sobreescribe la accion abajo.
		int jugadmasCercano = sp.balon().indiceMasCercano(sp.misJugadores());
		result.add(new ComandoIrA(jugadmasCercano, sp.balon()));
		
		Posicion[] misJugadores = sp.misJugadores();
		if (zonaDefensaActivada) {

			// Obtenemos todos los jugadores que est�n en la zona defensiva
			List<Integer> jugadDefensas = TacticaJmvCfUtils.obtenerJugadoresSegunZona(TacticaJmvCfUtils.ZonaCampo.DEFENSA, sp);

			// Son los jugadores rivales que ya est�n cubierto por alg�n defensa de mi equipo
			List<Integer> rivalesCubiertos = new ArrayList<Integer>();
			
			for (int jugador : jugadDefensas) {
				boolean esPortero = sp.detalleMisJugadores()[jugador]
						.esPortero();

				// Comprobamos los jugadores que pueden ir detr�s del bal�n o
				// detr�s de un delantero contrario
				int indiceRival = 0;
				for (Posicion posRival : sp.rivales()) {
					if ((sp.misJugadores())[jugador].distancia(posRival) < 10
							&& !esPortero && !rivalesCubiertos.contains(indiceRival)) {
						// Perseguimos al contrario
						double posRivalX = posRival.getX();
						double xFinal = 0;
						if (posRivalX <= 0) {
							xFinal = posRivalX + 2;
						} else {
							xFinal = posRivalX - 2;
						}
						Posicion posicionNueva = new Posicion(xFinal, posRival
								.getY() - 3);
						result.add(new ComandoIrA(jugador, posicionNueva));
						rivalesCubiertos.add(indiceRival);
					}
					indiceRival++;
				}

				if (!esPortero
						&& (sp.misJugadores())[jugador].distancia(sp.balon()) < (Constantes.DISTANCIA_CONTROL_BALON * 2)) {
					result.add(new ComandoIrA(jugador, sp.balon()));
				}
			}

			// Le damos las instrucciones al portero
			// Primero obtenemos el �ndice del portero
			int indicePortero = TacticaJmvCfUtils.obtenerIndicePortero(sp);
			Posicion posPorteroAntigua = sp.misJugadores()[indicePortero];
			double porteroX = 0;
			if (sp.balon().getX() < 0) {
				// porteroX = posPorteroAntigua.getX() - 0.05; // Va muy lento
				porteroX = 0 - 2;
			} else {
				// porteroX = posPorteroAntigua.getX() + 0.05; // Va muy lento
				porteroX = 0 + 2;
			}
			Posicion posPorteroNueva = new Posicion(porteroX, posPorteroAntigua
					.getY());
			if(esPosiblePosesionBalon && sp.balon().indiceMasCercano(sp.misJugadores()) == indicePortero && sp.balon().getX() < 8){
				result.add(new ComandoIrA(indicePortero, sp.balon()));	
			}else{
				result.add(new ComandoIrA(indicePortero, posPorteroNueva));	
			}
			

			// Comprobamos si alg�n defensa puede despejar el bal�n
			int[] puedenRematar = sp.puedenRematar();
			for (int ind : puedenRematar) {
				result.add(new ComandoGolpearBalon(ind, new Posicion(0, 0), 1,
						Constantes.ANGULO_VERTICAL));
			}

		}else if(zonaMedioCampoActivada){
			
			// Obtenemos todos los jugadores que est�n en la zona del mediocampo
			List<Integer> jugadMedioCampo = TacticaJmvCfUtils.obtenerJugadoresSegunZona(TacticaJmvCfUtils.ZonaCampo.MEDIOCAMPO, sp);
			
			int masCercano = sp.balon().indiceMasCercano(sp.misJugadores());
			result.add(new ComandoIrA(masCercano, sp.balon()));
			
			// Comprobamos si alg�n jugador puede despejar el bal�n o combinar el bal�n
			int[] puedenRematar = sp.puedenRematar();
			for (int ind : puedenRematar) {
//				result.add(new ComandoGolpearBalon(ind, new Posicion(0, 52.5), 1,
//						Constantes.ANGULO_VERTICAL));
				
//				System.out.println("Tiene el bal�n el jugador n�mero: " + sp.detalleMisJugadores()[ind].getNumero());
				int indiceSinMarca = TacticaJmvCfUtils.jugadorSinMarcaAleatorio(sp, sp.misJugadores()[ind],TacticaJmvCfUtils.ZonaCampo.DELANTERA);
				if(indiceSinMarca == -1){
					indiceSinMarca = TacticaJmvCfUtils.jugadorSinMarcaAleatorio(sp, sp.misJugadores()[ind],TacticaJmvCfUtils.ZonaCampo.MEDIOCAMPO);
				}
				if(indiceSinMarca == -1){
					indiceSinMarca = TacticaJmvCfUtils.jugadorSinMarcaAleatorio(sp, sp.misJugadores()[ind],TacticaJmvCfUtils.ZonaCampo.DEFENSA);
				}
				
				if(indiceSinMarca != -1){

//					System.out.println("Le pasa el bal�n al jugador n�mero: " + sp.detalleMisJugadores()[indiceSinMarca].getNumero());
					double distanciaGolpe = sp.misJugadores()[ind].distancia(sp.misJugadores()[indiceSinMarca]);
					double fuerzaGolpe = 1;
					final int distanciaMax = 15;
					if(distanciaGolpe < distanciaMax){
						fuerzaGolpe = distanciaGolpe / distanciaMax;
					}
//					System.out.println("Distancia: " + distanciaGolpe + ", Fuerza: " + fuerzaGolpe);
					
					
					result.add(new ComandoGolpearBalon(ind, sp.misJugadores()[indiceSinMarca], fuerzaGolpe,
							10));
				}
			}
			
			// Desmarcamos a los delanteros.
			List<Comando> desmarcar = TacticaJmvCfUtils.desmarcarJugadores(TacticaJmvCfUtils.ZonaCampo.DELANTERA, sp);
			result.addAll(desmarcar);
			
		}else if(zonaDelanteraActivada){
			
			// Obtenemos todos los jugadores que est�n en la zona de la delantera
			List<Integer> jugadDelanteros = TacticaJmvCfUtils.obtenerJugadoresSegunZona(TacticaJmvCfUtils.ZonaCampo.DELANTERA, sp);
			
//			// Desmarcamos a los delanteros.
//			List<Comando> desmarcar = TacticaBetisUtils.desmarcarJugadores(TacticaBetisUtils.ZonaCampo.DELANTERA, sp);
//			result.addAll(desmarcar);
			
			int masCercano = sp.balon().indiceMasCercano(sp.misJugadores());
			result.add(new ComandoIrA(masCercano, sp.balon()));
			
			// Comprobamos si alg�n delantero puede golpear el bal�n
			int[] puedenRematar = sp.puedenRematar();
			for (int ind : puedenRematar) {
				
				// Comprobamos que el jugador est� a la altura para rematar,
				// en caso contrario, avanzamos con el bal�n.
				if (sp.misJugadores()[ind].getY() < Constantes.centroArcoSup.getY()) {
					result.add(new ComandoIrA(ind, Constantes.centroArcoSup));
					result.add(new ComandoGolpearBalon(ind));
                }
				boolean chutar = false;
				if(TacticaJmvCfUtils.tieneRivalCerca(sp, ind)){
					chutar = true; 
				}
                if (chutar || sp.misJugadores()[ind].distancia(Constantes.centroArcoSup) < 25) {
                	result.add(new ComandoGolpearBalon(ind, Constantes.centroArcoSup, 1, 20));
                }
			}
		}

		if (sp.saco()) {
			int jugadorQueSaca = sp.balon().indiceMasCercano(sp.misJugadores());
			result.add(new ComandoIrA(jugadorQueSaca, sp.balon()));
		}

		return result;

	}
}